redact repository password from log output#114
Open
kinglike1337 wants to merge 1 commit into
Open
Conversation
The restic repository URL can carry the password inline as HTTP basic auth (rest:http://user:password@host:8000/path). This leaked the secret in two ways: - cli.status() logged config.repository verbatim at two INFO statements. - commands.run()/run_capture_std() logged the full restic command line (including -r <repo>) at DEBUG, so LOG_LEVEL=debug exposed the password on every backup/init/forget/prune/check run. Add utils.redact_repo_url(), which masks any embedded password (incl. "/" or "@" characters) with ***, and route all command and repository logging through it. Repository strings without credentials are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The restic repository URL can carry the password inline as HTTP basic auth, e.g.:
The password was leaking to the logs through two independent paths. This change redacts embedded credentials in all of them.
Leak paths fixed
1. Status logging (
cli.status())cli.status()loggedconfig.repositoryverbatim at twoINFOstatements, leaking the secret to stdout — and therefore into the cron log (> /proc/1/fd/1) on every scheduled run.Before:
After:
2. Command logging (
commands.run/run_capture_std)Every restic invocation flows through
commands.run()/run_capture_std(), which log the full command line:Since
restic()builds["restic", "-r", repository, ...], settingLOG_LEVEL=debugexposed the password on every backup / init / forget / prune / check / snapshots run. The fix is centralized: a newcommands._redacted_cmd()masks each argument before logging, so all current and future call sites are covered automatically.Changes
utils.redact_repo_url(repository)— masks any embedded password with***, robust against passwords containing/or@(handlesrest:/http:/https:basic auth; therest:backend prefix is preserved). Repository strings without credentials (s3:, local paths, key-basedsftp:) are returned unchanged. (Note: restic'ssftpbackend authenticates via ssh keys/agent and has no inline URL password, so baresftp:specs are intentionally not redacted.)commands.py— route all command logging through_redacted_cmd().cli.status()— wrap the two repository log statements inredact_repo_url().The actual restic invocations (
restic -r <repo> …) still receive the full, unredacted repository — only log output is masked.Testing
tests/unit/test_repository_redaction.py— basic-auth redaction,https, passwords with/and@, credentials-free repos unchanged, secret never present in output.tests/unit/test_command_redaction.py—run()andrun_capture_std()do not leak the password atDEBUG.blackandruff.Backward compatibility
No change to backups or restic invocations — only log output is affected.